//
//  ATAppDelegate.m
//  AutomationTool
//
//  Created by Laurie Marmon on 2/26/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#import "ATAppDelegate.h"
#import "ATScriptStepParameter.h"
#import "ATScriptStep.h"
#import "ATScript.h"
#import "ATScriptStepTemplate.h"
#import "ATScriptStepEditorView.h"
#import "ATTemplateManager.h"
#import "ATScriptSuite.h"

@interface ATAppDelegate ()

@property (nonatomic, strong) ATScriptSuite *scriptSuite;
//@property (nonatomic, strong) NSMutableArray *scripts;
@property (nonatomic, strong) NSArray *scriptStepTemplates;
@property (nonatomic, readonly) ATScriptStep *currentScriptStep;
@property (nonatomic, readonly) ATScript *currentScript;
@property (nonatomic, strong) NSIndexSet *currentScriptStepIndex;
@property (nonatomic, strong) NSIndexSet *currentScriptIndex;
@property (nonatomic, strong) NSIndexSet *selectedTemplateIndex;

@end

@implementation ATAppDelegate

@synthesize window = _window;
@synthesize sourceField = _sourceField;
@synthesize destinationField = _destinationField;
@synthesize editorView = _editorView;
@synthesize templateTableView = _templateTableView;
@synthesize scriptStepTableView = _scriptTableView;
@synthesize scriptsTableView = _scriptsTableView;
@synthesize applicationField = _applicationField;
@synthesize scriptField = _scriptField;
@synthesize executePanel = _executePanel;
@synthesize scriptSuite = _scriptSuite;
//@synthesize scripts = _scripts;
@synthesize scriptStepTemplates = _scriptStepTemplates;
@synthesize currentScript = _currentScript;
@synthesize currentScriptStepIndex = _currentScriptStepIndex;
@synthesize currentScriptIndex = _currentScriptIndex;
@synthesize selectedTemplateIndex = _selectedTemplateIndex;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    [self setupNewScriptSuite];
    self.scriptStepTemplates = [[ATTemplateManager sharedManager] allTemplates];
    self.editorView.delegate = self;
}

- (void)setupNewScriptSuite
{
    self.currentScriptStepIndex = [NSIndexSet indexSet];
    self.currentScriptIndex = [NSIndexSet indexSet];
    [self.editorView drawViewForScriptStep:self.currentScriptStep];
    self.selectedTemplateIndex = [NSIndexSet indexSet];
    self.scriptSuite = [[ATScriptSuite alloc] init];
}

- (IBAction)close:(id)sender
{
    NSSavePanel *saveScriptPanel = [NSSavePanel savePanel];
    [saveScriptPanel setNameFieldStringValue:@"ScriptSuite.plist"];
    [saveScriptPanel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result){
        if (result == NSFileHandlingPanelOKButton) {
            NSURL*  theFile = [saveScriptPanel URL];
            
            NSMutableData *data = [[NSMutableData alloc] init];
            NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];          
            [archiver encodeObject:self.scriptSuite forKey:@"ATScriptSuite"];
            [archiver finishEncoding];
            NSError *error;
            [data writeToFile:[theFile path] options:NSDataWritingAtomic error:&error];
        }
        [self setupNewScriptSuite];
    }];
    
}

- (IBAction)save:(id)sender
{
    NSSavePanel *saveScriptPanel = [NSSavePanel savePanel];
    [saveScriptPanel setNameFieldStringValue:@"ScriptSuite.plist"];
    [saveScriptPanel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result){
        if (result == NSFileHandlingPanelOKButton) {
            NSURL*  theFile = [saveScriptPanel URL];
            
            NSMutableData *data = [[NSMutableData alloc] init];
            NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];          
            [archiver encodeObject:self.scriptSuite forKey:@"ATScriptSuite"];
            [archiver finishEncoding];
            NSError *error;
            [data writeToFile:[theFile path] options:NSDataWritingAtomic error:&error];
        }
    }];
}

- (IBAction)open:(id)sender 
{
    NSOpenPanel *openScriptPanel = [NSOpenPanel openPanel];
    [openScriptPanel setCanChooseFiles:YES];
    [openScriptPanel setCanCreateDirectories:NO];
    [openScriptPanel setAllowsMultipleSelection:NO];
    [openScriptPanel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result){
        [self setupNewScriptSuite];
        if (result == NSFileHandlingPanelOKButton) {
            NSURL *fileToOpen = [[openScriptPanel URLs] objectAtIndex:0];
            NSData *codedData = [[NSData alloc] initWithContentsOfFile:[fileToOpen path]];
            
            NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:codedData];
            self.scriptSuite = [unarchiver decodeObjectForKey:@"ATScriptSuite"];
        }
    
    }];
}

- (IBAction)browseForApp:(id)sender 
{
    NSOpenPanel *browseScriptPanel = [NSOpenPanel openPanel];
    [browseScriptPanel setCanChooseFiles:YES];
    [browseScriptPanel setCanCreateDirectories:NO];
    [browseScriptPanel setAllowsMultipleSelection:NO];
    [browseScriptPanel beginSheetModalForWindow:self.executePanel completionHandler:^(NSInteger result){
        if (result == NSFileHandlingPanelOKButton) {
            NSURL *fileToOpen = [[browseScriptPanel URLs] objectAtIndex:0];
            self.applicationField.stringValue = [fileToOpen absoluteString];
            
        }
        
    }];
}

- (IBAction)browseForScripts:(id)sender 
{
    NSOpenPanel *browseScriptPanel = [NSOpenPanel openPanel];
    [browseScriptPanel setCanChooseFiles:YES];
    [browseScriptPanel setCanCreateDirectories:NO];
    [browseScriptPanel setAllowsMultipleSelection:NO];
    [browseScriptPanel beginSheetModalForWindow:self.executePanel completionHandler:^(NSInteger result){
        if (result == NSFileHandlingPanelOKButton) {
            NSURL *fileToOpen = [[browseScriptPanel URLs] objectAtIndex:0];
            self.scriptField.stringValue = [fileToOpen absoluteString];
            
        }
        
    }];
}

- (IBAction)exportJavaScriptForCurrentScript:(id)sender
{
    NSSavePanel *saveScriptPanel = [NSSavePanel savePanel];
    [saveScriptPanel setNameFieldStringValue:@"SampleJavaScript.js"];
    [saveScriptPanel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result){
        if (result == NSFileHandlingPanelOKButton) {
            NSURL *theFile = [saveScriptPanel URL];
            NSError *error;
            //save some files along with the export file
            NSURL *destinationPath = [theFile URLByDeletingLastPathComponent];
            destinationPath = [destinationPath URLByAppendingPathComponent:@"ATLibrary.js"];
            NSFileManager *fileManager = [NSFileManager defaultManager];
            if ([fileManager fileExistsAtPath:[destinationPath relativePath]]) {
                [fileManager removeItemAtURL:destinationPath error:&error];
            }
            NSURL *sourceURL = [[NSBundle mainBundle] URLForResource:@"ATLibrary" withExtension:@"js"];
            [fileManager copyItemAtURL:sourceURL toURL:destinationPath error:&error];
            
            NSString *javaScriptCode = [self generateJavaScriptCodeforCurrentScript];
            [javaScriptCode writeToURL:theFile atomically:YES encoding:NSUTF8StringEncoding error:&error];
        }
    }];
}

- (IBAction)exportJavaScriptForScriptSuite:(id)sender 
{
    NSSavePanel *saveScriptPanel = [NSSavePanel savePanel];
    [saveScriptPanel setNameFieldStringValue:@"SampleJavaScript.js"];
    [saveScriptPanel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result){
        if (result == NSFileHandlingPanelOKButton) {
            NSURL*  theFile = [saveScriptPanel URL];
            
            NSString *javaScriptCode = [self generateJavaScriptCodeforScriptSuite];
            NSError *error;
            //save some files along with the export file
            NSURL *destinationPath = [theFile URLByDeletingLastPathComponent];
            destinationPath = [destinationPath URLByAppendingPathComponent:@"ATLibrary.js"];
            NSFileManager *fileManager = [NSFileManager defaultManager];
            if ([fileManager fileExistsAtPath:[destinationPath relativePath]]) {
                [fileManager removeItemAtURL:destinationPath error:&error];
            }
            NSURL *sourceURL = [[NSBundle mainBundle] URLForResource:@"ATLibrary" withExtension:@"js"];
            [fileManager copyItemAtURL:sourceURL toURL:destinationPath error:&error];
            [javaScriptCode writeToURL:theFile atomically:YES encoding:NSUTF8StringEncoding error:&error];
        }
    }];
}

- (IBAction)deleteRow:(id)sender 
{
    if ([self.window firstResponder] == self.scriptStepTableView) {
        NSInteger selectedRowNum = [self.scriptStepTableView selectedRow];
        if (selectedRowNum != -1) {
            ATScriptStep *stepToRemove = [self.currentScript.scriptSteps objectAtIndex:selectedRowNum];
            [self.currentScript removeScriptStep:stepToRemove ofType:ATScriptStepTypeNormal];
            
            //determine where the next selection will be
            if ([self.currentScript.scriptSteps count] > selectedRowNum) {
                self.currentScriptStepIndex  = [NSIndexSet indexSetWithIndex:selectedRowNum];
                [self.editorView drawViewForScriptStep:[self.currentScript.scriptSteps objectAtIndex:selectedRowNum]];
            } else if (selectedRowNum != 0) {
                self.currentScriptStepIndex  = [NSIndexSet indexSetWithIndex:selectedRowNum-1];
                [self.editorView drawViewForScriptStep:[self.currentScript.scriptSteps objectAtIndex:selectedRowNum-1]];
            } else {
                [self.editorView resetDefaultView];
            }
        }
 
    }
}

- (IBAction)newScript:(id)sender 
{    
    //reset the application for a new script
    ATScript *script = [[ATScript alloc] init];
    self.currentScriptStepIndex = [NSIndexSet indexSet];
    [self.editorView drawViewForScriptStep:self.currentScriptStep];
    [self.scriptSuite insertScript:script atIndex:[[self.scriptSuite scripts] count]];
    self.currentScriptIndex = [NSIndexSet indexSetWithIndex:[self.scriptSuite.scripts count]-1];
    
    //insert 3 helper log message script steps
    [self insertScriptStepWithTemplate:[[ATTemplateManager sharedManager] templateWithName:@"Log Message"]];
    [self.currentScriptStep setValue:@"\"Start Setup Steps...\"" forParameterName:@"Message"];
    [self insertScriptStepWithTemplate:[[ATTemplateManager sharedManager] templateWithName:@"Log Message"]];
    [self.currentScriptStep setValue:@"\"Start Test Steps...\"" forParameterName:@"Message"];
    [self insertScriptStepWithTemplate:[[ATTemplateManager sharedManager] templateWithName:@"Log Message"]];
    [self.currentScriptStep setValue:@"\"Start Reset Steps...\"" forParameterName:@"Message"];
    [self.editorView drawViewForScriptStep:nil];

}

- (IBAction)generateJavaScript:(id)sender 
{
    self.destinationField.stringValue = [self generateJavaScriptCodeforCurrentScript];
}

- (IBAction)execute:(id)sender {
}

- (IBAction)moveScriptStepUp:(id)sender 
{
    NSInteger row = [self.currentScriptStepIndex firstIndex];
    //if greater than 0, we can move it up
    if (row > 0) {
        [self.currentScript reorderScriptStep:self.currentScriptStep atIndex:row ofType:ATScriptStepTypeNormal toIndex:row-1];
        self.currentScriptStepIndex = [NSIndexSet indexSetWithIndex:row-1];
    }
}

- (IBAction)moveScriptStepDown:(id)sender
{
    NSInteger row = [self.currentScriptStepIndex firstIndex];
    //if less than count of scriptSteps in the currentScript
    if (row < [self.currentScript.scriptSteps count]-1) {
        [self.currentScript reorderScriptStep:self.currentScriptStep atIndex:row ofType:ATScriptStepTypeNormal toIndex:row+1];
        self.currentScriptStepIndex = [NSIndexSet indexSetWithIndex:row+1];
    }
}

- (NSString *)generateJavaScriptCodeforScriptSuite 
{
    NSString *importString = @"#import \"ATLibrary.js\"";
    NSString *targetVarString = @"var target = UIATarget.localTarget();";
    NSString *windowVarString = @"var window = app.mainWindow();";
    NSString *returnString = @"\n";

    NSMutableArray *javaScriptLines = [[NSMutableArray alloc] initWithObjects:importString, returnString, targetVarString, windowVarString, returnString, nil];

    for (ATScript *script in self.scriptSuite.scripts) {
        [javaScriptLines addObject:[self generateJavaScriptCodeforScript:script]];
    }
    return [javaScriptLines componentsJoinedByString:@"\n"];
}

- (NSString *)generateJavaScriptCodeforCurrentScript 
{
    NSString *importString = @"#import \"ATLibrary.js\"";
    NSString *targetVarString = @"var target = UIATarget.localTarget();";
    NSString *windowVarString = @"var window = app.mainWindow();";
    NSString *returnString = @"\n";
    
    NSMutableArray *javaScriptLines = [[NSMutableArray alloc] initWithObjects:importString, returnString, targetVarString, windowVarString, returnString, nil];
    
    [javaScriptLines addObject:[self generateJavaScriptCodeforScript:self.currentScript]];
    return [javaScriptLines componentsJoinedByString:@"\n"];
}

- (NSString *)generateJavaScriptCodeforScript:(ATScript *)script
{
    //for indention purposes
    NSMutableArray *tabs = [[NSMutableArray alloc] init]; 
    NSString *tabString = @"\t";
    NSInteger tabCount = 0;
    
    //script identifying code
    NSString *logStart = [NSString stringWithFormat:@"UIALogger.logStart(\"%@\");", script.name];
    NSMutableArray *javaScriptLines = [[NSMutableArray alloc] initWithObjects:logStart, nil];
    for (ATScriptStep *scriptStep in script.scriptSteps) {
        //determine if we can decrease the indentation
        if ([scriptStep.name isEqualToString:@"End If"]) {
            tabCount -= 1;
            [tabs removeObjectAtIndex:[tabs count]-1];
        }
        
        //processing the script step
        NSString *javaScriptTemplate = scriptStep.stepTemplate.codeTemplate;
        for (NSString *parameterName in scriptStep.parameterNames) {
            id parameterValue = [scriptStep valueForParameterName:parameterName];
            NSString *formattedParameterString = [NSString stringWithFormat:@"#{%@}", parameterName];
            javaScriptTemplate = [javaScriptTemplate stringByReplacingOccurrencesOfString:formattedParameterString withString:parameterValue];
        }
        
        NSString *indentString = (tabCount > 0) ? [tabs componentsJoinedByString:@""] : @"";
        [javaScriptLines addObject:[NSString stringWithFormat:@"%@%@", indentString, javaScriptTemplate]];
        
        //determine if the next lines need more indentation
        if ([scriptStep.name isEqualToString:@"If (condition)"]) {
            tabCount += 1;
            [tabs addObject:tabString];
        }
    }
    [javaScriptLines addObject:@"\n"];
    return [javaScriptLines componentsJoinedByString:@"\n"];
}


- (void)addScriptStep 
{
    //determine the template of the new step to be added:
    //NSInteger rowNumber = [self.templateTableView selectedRow];
    ATScriptStepTemplate *template = [self.scriptStepTemplates objectAtIndex:[self.selectedTemplateIndex firstIndex]];
    [self insertScriptStepWithTemplate:template];
}

- (void)insertScriptStepWithTemplate:(ATScriptStepTemplate *)template
{
    //determine where the new step will be added in the current script:
    NSInteger currentStepIndex = [self.scriptStepTableView selectedRow];
    NSInteger indexForNewStep = (currentStepIndex == -1 || currentStepIndex == [self.currentScript.scriptSteps count]-1) ? [self.currentScript.scriptSteps count] : currentStepIndex+1;
    
    //create the new ATScriptStep:
    ATScriptStep *newStep = [[ATScriptStep alloc] init];
    [newStep setScriptStepTemplate:template];
     
    [self.currentScript insertScriptStep:newStep atIndex:indexForNewStep ofType:ATScriptStepTypeNormal];
    self.currentScriptStepIndex  = [NSIndexSet indexSetWithIndex:indexForNewStep];
    [self.scriptStepTableView scrollRowToVisible:[self.currentScriptStepIndex firstIndex]];
    [self.editorView drawViewForScriptStep:newStep];
    
    //add that if the script step is "if" also add in the "end if" step:
    if ([newStep.name isEqualToString:@"If (condition)"]) {
        [self insertScriptStepWithTemplate:[[ATTemplateManager sharedManager] templateWithName:@"End If"]];
        self.currentScriptStepIndex = [NSIndexSet indexSetWithIndex:indexForNewStep];
        [self.editorView drawViewForScriptStep:newStep];
    }
}

- (void)editorView:(ATScriptStepEditorView *)view didChangeParameterName:(NSString *)name toValue:(NSString *)value
{
    ATScriptStep *scriptStep = self.currentScriptStep;
    [scriptStep setValue:value forParameterName:name];
    [self.currentScript updateScriptStep:scriptStep ofType:ATScriptStepTypeNormal];
}

- (ATScriptStep *)currentScriptStep
{
    if (self.currentScriptStepIndex.count > 0) {
        return [self.currentScript.scriptSteps objectAtIndex:self.currentScriptStepIndex.firstIndex];
    }
    else {
        return nil;
    }
}

- (ATScript *)currentScript
{
    if (self.currentScriptIndex.count > 0) {
        return [self.scriptSuite.scripts objectAtIndex:self.currentScriptIndex.firstIndex];
    }
    else {
        return nil;
    }
}

- (void)setCurrentScriptStepIndex:(NSIndexSet *)currentScriptStepIndex
{
    [self willChangeValueForKey:@"currentScriptStep"];
    _currentScriptStepIndex = currentScriptStepIndex;
    [self didChangeValueForKey:@"currentScriptStep"];
}

- (void)setCurrentScriptIndex:(NSIndexSet *)currentScriptIndex 
{
    [self willChangeValueForKey:@"currentScript"];
    _currentScriptIndex = currentScriptIndex;
    [self didChangeValueForKey:@"currentScript"];
}

- (void)setSelectedTemplateIndex:(NSIndexSet *)selectedTemplateIndex
{
    [self willChangeValueForKey:@"selection"];
    _selectedTemplateIndex = selectedTemplateIndex;
    [self didChangeValueForKey:@"selection"];
}

- (BOOL)tableView:(NSTableView *)view shouldSelectRow:(NSInteger)row
{
    if ([self.scriptStepTableView isEqual:view]) {
        self.currentScriptStepIndex = [NSIndexSet indexSetWithIndex:row];
        [self.editorView drawViewForScriptStep:self.currentScriptStep];
        return YES;
    } else if ([self.templateTableView isEqual:view]){
        return YES;
    } else if ([self.scriptsTableView isEqual:view]) {
        self.currentScriptIndex = [NSIndexSet indexSetWithIndex:row];
        self.currentScriptStepIndex = [NSIndexSet indexSet];
        [self.editorView drawViewForScriptStep:self.currentScriptStep];
        return YES;
    }else {
        return NO;
    }
}

- (IBAction)showCustomSheet:(id)sender
{

    [NSApp beginSheet: self.executePanel
       modalForWindow: self.window
        modalDelegate: self
       didEndSelector: @selector(didEndSheet:returnCode:contextInfo:)
          contextInfo: nil];
    [self.executePanel makeKeyAndOrderFront:self]; 
}

- (IBAction)closeMyCustomSheet:(id)sender
{
    [NSApp endSheet:self.executePanel];
    
    if (![self.applicationField.stringValue isEqualToString:@""] &&
        ![self.scriptField.stringValue isEqualToString:@""]){
        NSString *scriptLocation = [self.scriptField.stringValue stringByReplacingOccurrencesOfString:@"file://localhost" withString:@""];
        NSString *scriptDirectory = [scriptLocation stringByReplacingOccurrencesOfString:[scriptLocation lastPathComponent] withString:@""];
        NSString *libraryLocation = [scriptDirectory stringByAppendingString:@"ATLibrary.js"];
        NSString *traceLocation = [scriptDirectory stringByAppendingString:@"data.trace"];
        
        //call terminal stuff
        NSArray *arguments = [NSArray arrayWithObjects:
                              @"-t", 
                              @"/Developer/Platforms/iPhoneOS.platform/Developer/Library/Instruments/PlugIns/AutomationInstrument.bundle/Contents/Resources/Automation.tracetemplate",
                              @"-D",
                              //@"/Users/laurie/Desktop/FinalTest/data.trace",
                              traceLocation,
                              [self.applicationField.stringValue stringByReplacingOccurrencesOfString:@"file://localhost"   withString:@""],
                              @"-e",
                              @"UIASCRIPT",
                              libraryLocation,
                              @"-e",
                              @"UIASCRIPT",
                              scriptLocation,
                              @"-e",
                              @"UIARESULTSPATH",
                              scriptDirectory,
                              nil];
        NSTask *task = [NSTask launchedTaskWithLaunchPath:@"/usr/bin/instruments" arguments:arguments];
        task.terminationHandler = ^(NSTask *task){
            NSTask *anotherTask = [NSTask launchedTaskWithLaunchPath:@"/usr/bin/open" arguments:[NSArray arrayWithObject:traceLocation]];
        };
    }
}

- (void)didEndSheet:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
{
    [sheet orderOut:self];
}

@end
